perm filename FASFRK.JP[LIB,LSP] blob
sn#864797 filedate 1977-07-20 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00004 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 SAIL MACLISP Interjob Communication Facility
C00008 00003 Short description of available forking functions
C00010 00004 An example of how to setup two forks
C00013 ENDMK
C⊗;
SAIL MACLISP Interjob Communication Facility
--------------------------------------------
By: JP (Jorge Phillips) @ SAIL
A preliminary version of a MACLISP interjob communication facility is
available to all lusers subscribing to the (help) autoload facility.
These functions permit arbitrary creation, deletion, synchronization and
intercommunication of MACLISP processes (SAIL jobs). For the sake of a
better name, and to confuse everybody we will refer to MACLISP jobs as
forks (although there is no hierarchical structure between jobs as the
name would imply).
Forks are uniquely identified by job number (assigned by SAIL-10) during
their existence. To a MACLISP job a fork is identified by its fork handle,
which is nothing but its FIXNUMified job number. There are functions for
creating parent and child MACLISP processes, and to suspend them. There
are also functions for sending sxprs between forks and for busy-waiting
and/or blocking for messages either from particular forks or of a
particular value.
The process of creating and using forks is as follows:
- forks that will be called below the monitor top-level must execute
the subr sfork in order to suspend themselves in a nice way
These forks are ssaved as dump files to be called by their
parent fork.
- A suspended fork ssaved on DSK: is reactivated by the CFORK subr.
This subr must be applied by the parent fork (the creator), and
starts the child fork exactly after the SFORK that suspended it.
- CFORK and SFORK return the fork handles for the created child fork
and for the parent fork respectively. They also set the global
vars UPFORK# (in the child) and LOWFRK# (in the parent).
- A child fork (i.e. a non-top level fork) kills itself and dissapears
by applying (quit)
- So does the top-level MACLISP job.
NOTICE: If a fork hits a LISP error condition, it will NOT kill itself.
You will have to kill it manually, or advise somehow the LISP error
handler to execute a (quit) previously having sent some kind of death
message to its parent (unless the parent fork doesnt care, which is
unlikely). Better even, you might have the fork send back to its parent
some message and let the parent decide what action to take. You may attach
to a fork to regain control of the tty, and take whatever action is
appropriate in the break.
Intercommunication
------------------
MACLISP interjob mesages are of the format (fork-handle . message) where
message is an sxpr (atoms allowed). A typical message might be:
(27 . hi)
which means that it was originated from fork 27, and the message is the
atom hi. Messages can be of up to 5120 chars including parens, blanks,
escape chars etc. This allows to send messages of at most 10 pages of
tightly packed parens, which should be sufficient for most applications.
If you need messages of a larger size, you'd better write them in a file,
and send messages with the file name. You will clearly have to synchronize
the file reading and writing.
NOTE: Losing MACLISP screws up transmission of |..| atoms. They will arrive
w/o the |..|. Thus, |a b foo| will be received as a b foo. BEWARE!!
Short description of available forking functions
------------------------------------------------
cfork[(filnam ext p pn)] SUBR
Starts up a suspended fork. Sets global lowfrk# to fork
handle. Returns this as value in case you want to use it
for something else
sfork[] SUBR
Suspends fork and returns when CFORKed, the parent's handle.
It also sets global UPFORK# to the handle.
msg[frk# sxpr] SUBR
Sends s-expression sxpr to fork frk#. It returns T if
succesful, NIL if the fork is busy reading a msg, or NOJOB if
the fork is non-existent. If NIL is returned the message
must be resent.
gmsg[] SUBR
Blocks calling process, waiting for message from anybody.
Returns message as dotted pair (frk# . sxpr). No software
interrupts (such as ↑G) are acknowledged in this state.
waitmsg[msg frk#] SUBR
Busy waits for a message EQ to msg from fork FRK#. NILs
act as wildcards. A frk# of NIL accepts a message from ANY
fork. A msg NIL accepts any message. Clearly
waitmsg[nil;nil] is equivalent to gmsg[]
mail?[] SUBR
T if msg waiting, NIL otherwise.
An example of how to setup two forks
------------------------------------
;;; Upper fork initialization functions. To get a SUSPENDed version do
;;; (start-forking) at top-level Lisp.
;;; This would be a file to EREAD into a clean LISP to create a parent fork.
;;; In this case, the parent fork calls the lower fork to reverse an sxpr
;;; if the sxpr is a list or listify it if it is an atom. If it gets something
;;; else, the lower fork will bomb (no type checking is done).
(defun fork-read nil
(terpri)(princ '|-->|)(read))
(defun fork-print nil
(princ '|from frk: |)(princ (cdr (gmsg)) ))
(defun fork-fork nil
(do ((x (fork-read) (fork-read)))
((eq x 'end) (prog2 (print ':kill) (quit)))
(msg lowfrk# x)
(fork-print) ))
(defun start-forking nil
(suspend)
(cfork (prog2 (princ '|Lower fork name? |)(read)))
(fork-fork) )
⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗⊗
;;; down fork initialization fns. To get a SUSPENDed version do (start-forking)
;;; at top-level Lisp. Fork dissapears magically previously having sent the message
;;; (DIE! DIE!) to its parent
;;; And you would EREAD this into another LISP to get the suspended version of
;;; the child fork.
(defun fork-fork nil
(do ((x (cdr (gmsg)) (cdr (gmsg)) ))
((eq x 'STOP)(msg upfork# '(die! die!))(quit))
(msg upfork# (cond ((atom x)(list x))
(t (reverse x))))))
(defun start-forking nil
(prog2 (sfork)(fork-fork)))